#include "GameScene.h"
#include "../../Utils/PlatTypeUtil.h"
#include "../../Utils/LogUtil.h"
#include "../../Templates/NewObject.h"
#include "Entity.h"
#include "../../Input/Input.h"
#include "../../Render/RenderState.h"
#include "../../Core/CoreGlobals.h"
#include "../../Core/MaggotApp.h"
#include "../../Render/Imgui/imgui.h"

GameScene::GameScene()
{
	
}

Entity* GameScene::GetEntityById(uint64 id)
{
	if (mEntitys.find(id) != mEntitys.end())
		return mEntitys.find(id)->second;
	assert(0);
	return nullptr;
}

Entity* GameScene::GetEntityByName(const std::string& name)
{
	for (const auto& entityIter : mEntitys)
	{
		if (entityIter.second->GetName() == name)
			return entityIter.second;
	}
	assert(0);
	return nullptr;
}

Camera& GameScene::GetCamera()
{
	return mCamera;
}

entt::registry& GameScene::GetRegistry()
{
	return mRegistry;
}

void GameScene::ClearEntitys()
{
	mRegistry.each([&](auto entity)
		{ mRegistry.destroy(entity); });
	mRegistry.clear();

	for (auto& entityIter : mEntitys)
	{
		entityIter.second->ReleaseResource();
	}
	mEntitys.clear();
}

void GameScene::OnResize()
{
	// Run at game thread
	float aspect = (float)GRenderState->GetWidth() / GRenderState->GetHeight();
	AsyncTask(GGameThreadId, [this, aspect]() {
		mCamera.SetLens(0.25f * glm::pi<float>(), aspect, 0.5f, 100.0f);
		});

	for (uint32 i = 0; i < GRenderState->mRenderProcessMap.size(); ++i)
	{
		GRenderState->mRenderProcessMap[i]->OnResize();
	}
}

void GameScene::OnFrameEnd()
{
	for (uint32 i = 0; i < GRenderState->mRenderProcessMap.size(); ++i)
	{
		GRenderState->mRenderProcessMap[i]->OnFrameEnd();
	}
}

void GameScene::OnImgui()
{
	// ImGui::ShowDemoWindow();

	if (ImGui::BeginMainMenuBar())
	{
		ImGui::Text("Fps : %d", GRenderState->GetFps());

		// ImGui::SliderFloat3("Camera", (float*)&mCamera.mPosition, -1000.f, 1000.f);

		ImGui::EndMainMenuBar();
	}
}

void GameScene::Init()
{
	mCamera.LookAt(glm::vec3(0.f, 5.f, 5.f), glm::vec3(0.f, 0.f, 0.f));
	mCamera.SetLens(0.25f * glm::pi<float>(), (float)GRenderState->GetWidth() / GRenderState->GetHeight(), 0.5f, 100.0f);
	mCamera.UpdateViewMatrix();

	for (uint32 i = 0; i < GRenderState->mRenderProcessMap.size(); ++i)
	{
		GRenderState->mRenderProcessMap[i]->Init(this);
	}
	OnInit();
	for (uint32 i = 0; i < GRenderState->mRenderProcessMap.size(); ++i)
	{
		GRenderState->mRenderProcessMap[i]->OnInit();
	}
}

void GameScene::Exit()
{
	OnExit();
	ClearEntitys();

	for (uint32 i = 0; i < GRenderState->mRenderProcessMap.size(); ++i)
	{
		GRenderState->mRenderProcessMap[i]->OnExit();
	}
}

void GameScene::Tick(float deltaTime)
{
	if (Input::Get().IsKeyDown(Keyboard::W))
		mCamera.Walk(deltaTime);

	if (Input::Get().IsKeyDown(Keyboard::S))
		mCamera.Walk(-1.f * deltaTime);

	if (Input::Get().IsKeyDown(Keyboard::A))
		mCamera.Strafe(deltaTime);

	if (Input::Get().IsKeyDown(Keyboard::D))
		mCamera.Strafe(-1.f * deltaTime);

	if (Input::Get().IsKeyDown(Keyboard::E))
		mCamera.Rise(deltaTime);

	if (Input::Get().IsKeyDown(Keyboard::Q))
		mCamera.Rise(-1.f * deltaTime);

	if (Input::Get().RightButton())
	{
		float dx = static_cast<float>(Input::Get().MouseX() - Input::Get().LastMouseX());
		float dy = static_cast<float>(Input::Get().MouseY() - Input::Get().LastMouseY());

		mCamera.Pitch(dy);
		mCamera.RotateY(-1.f * dx);
	}

	mCamera.UpdateViewMatrix();

	OnTick(deltaTime);
	// entity tick
	for (const auto& entityIter : mEntitys)
	{
		entityIter.second->Tick(deltaTime);
	}

	// Run Render Graph
	for (uint32 i = 0; i < GRenderState->mRenderProcessMap.size(); ++i)
	{
		GRenderState->mRenderProcessMap[i]->OnTick(deltaTime);
	}
}
